/*
 * LogEx a Java library for extracting log file data
 * Copyright 2012 LogEx Team.
 *
 * This program is free software. You can distribute or modify it under the 
 * terms of the GNU Lesser General Public License version 3.0 as published by  
 * the Free Software Foundation.
 *
 * This program is distributed AS IS and WITHOUT WARRANTY. OF ANY KIND,
 * INCLUDING MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, contact the Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
package org.logex.main;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.xml.xquery.XQException;

import org.basex.api.DatabaseHandler;
import org.logex.obj.Sibling;

/**
 * Performs the task of writing Log Entry bundles to the database.
 * 
 * @author Lohitha Chiranjeewa
 */
public class XmlWriter {

	private DatabaseHandler databaseHandler;
	private AsciiParser asciiParser;
	private ArrayList<String> documentList;
	private File file;
	private FileWriter fwstream;
	private BufferedWriter out;
	private StringBuffer stringBuffer;
	private String fullLogLine;
	private int logEntryCount;
	private static final int LOG_ENTRY_LIMIT = 250;

	/**
	 * Constructor for <code>XmlParser</code> class.
	 * 
	 * @param parserReader
	 *            Incoming <code>ParserReader</code> object
	 */
	public XmlWriter(AsciiParser parserReader) {
		try {
			databaseHandler = new DatabaseHandler();
		} catch (IOException e1) {
			e1.printStackTrace();
		} catch (XQException e1) {
			e1.printStackTrace();
		}
		this.asciiParser = parserReader;
		documentList = new ArrayList<String>();
		logEntryCount = 0;
	}

	/**
	 * Prepares the Log Entry bundle without sibling elements.
	 * 
	 * @param tag
	 *            Element name
	 * @param xmlMap
	 *            The Map containing basic XML elements to be written
	 * @param docName
	 *            Name of the XML document
	 * @return Boolean true value if operation is successful
	 * @throws IOException
	 *             Due to errors in writing to file
	 * @throws XQException
	 *             If reasons such as wrong commands, DB errors occur
	 */
	public boolean bundleWithoutSiblings(String tag,
			Map<String, String> xmlMap, String docName) throws IOException,
			XQException {
		if (logEntryCount == 0) {
			stringBuffer = new StringBuffer();
		}
		if (!xmlMap.isEmpty()) {
			stringBuffer.append("<" + tag + ">" + "\n");

			for (Map.Entry<String, String> pairs : xmlMap.entrySet()) {
				stringBuffer
						.append("<" + pairs.getKey() + ">" + pairs.getValue()
								+ "</" + pairs.getKey() + ">" + "\n");
			}
			stringBuffer.append("</" + tag + ">" + "\n");
		} else {
			fullLogLine = asciiParser.getFullLogLine();
			fullLogLine = fullLogLine.replaceAll("&", "&amp;");
			fullLogLine = fullLogLine.replaceAll("<", "&lt;");
			fullLogLine = fullLogLine.replaceAll(">", "&gt;");
			stringBuffer.append(StringConstants.UNID_LINE_START_TAG
					+ fullLogLine + StringConstants.UNID_LINE_END_TAG + "\n");
		}
		logEntryCount++;
		writeBundleToDb(docName);
		return true;
	}

	/**
	 * Prepares the Log Entry bundle with sibling elements.
	 * 
	 * @param xmlMapList
	 *            The List containing a set of xmlMap objects
	 * @param docName
	 *            Name of the XML document
	 * @return Boolean true value if operation is successful
	 * @throws IOException
	 *             Due to errors in writing to file
	 * @throws XQException
	 *             If reasons such as wrong commands, DB errors occur
	 */
	public boolean bundleWithSiblings(List<Sibling> xmlMapList, String docName)
			throws IOException, XQException {
		if (logEntryCount == 0) {
			stringBuffer = new StringBuffer();
		}
		for (int i = 0; i < xmlMapList.size(); i++) {
			stringBuffer.append("<" + xmlMapList.get(i).getTagName() + ">"
					+ "\n");
			for (Map.Entry<String, String> intPairs : xmlMapList.get(i)
					.getXmlMap().entrySet()) {
				stringBuffer.append("<" + intPairs.getKey() + ">"
						+ intPairs.getValue() + "</" + intPairs.getKey() + ">"
						+ "\n");
			}
			if (i != 0) {
				stringBuffer.append("</" + xmlMapList.get(i).getTagName() + ">"
						+ "\n");
			}
		}
		stringBuffer.append("</" + xmlMapList.get(0).getTagName() + ">" + "\n");
		logEntryCount++;
		writeBundleToDb(docName);
		return true;
	}

	/**
	 * Writes the outermost elements of the XML document to the database.
	 * 
	 * @param docName
	 *            Name of the XML document
	 * @return Boolean true value if operation is successful
	 * @throws IOException
	 *             Due to errors in writing to file
	 * @throws XQException
	 *             If reasons such as wrong commands, DB errors occur
	 */
	public boolean writeOutermostElements(String docName) throws IOException,
			XQException {
		if (!checkDocumentExistence(docName)) {
			file = new File(System.getProperty(StringConstants.USER_DIR)
					+ File.separator + docName);
			file.createNewFile();
			fwstream = new FileWriter(
					System.getProperty(StringConstants.USER_DIR)
							+ File.separator + docName);
			out = new BufferedWriter(fwstream);
			out.write(StringConstants.LOG_FILE_START_TAG + "\n"
					+ StringConstants.NOTICE_START_TAG
					+ StringConstants.LOGEX_TEAM_MSG
					+ StringConstants.NOTICE_END_TAG + "\n"
					+ StringConstants.LOG_FILE_END_TAG);
			out.close();
			databaseHandler.addFile(docName);
			file.delete();
		}
		return true;
	}

	/**
	 * Checks if a document exists under the current name.
	 * 
	 * @param docName
	 *            Name of the XML document
	 * @return Boolean value of the existence of the file
	 * @throws XQException
	 *             If reasons such as wrong commands, DB errors occur
	 */
	public boolean checkDocumentExistence(String docName) throws XQException {
		String trimmedDoc;
		documentList = databaseHandler.getDocumentNames();
		for (String document : documentList) {
			trimmedDoc = document.substring(document.lastIndexOf("/") + 1,
					document.length());
			if (docName.equals(trimmedDoc)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Writes the Log Entry Bundle to the database if the conditions are
	 * fulfilled.
	 * 
	 * @param docName
	 *            Name of the XML document
	 * @throws XQException
	 *             If reasons such as wrong commands, DB errors occur
	 */
	public void writeBundleToDb(String docName) throws XQException {
		if (logEntryCount == LOG_ENTRY_LIMIT
				|| asciiParser.getStreamLine() == null) {
			databaseHandler.updateFile(
					docName,
					StringConstants.ENTRY_BUNDLE_START_TAG
							+ stringBuffer.toString()
							+ StringConstants.ENTRY_BUNDLE_END_TAG);
			logEntryCount = 0;
		}
	}

}
